package ar.edu.unicen.pladema.vc1.formats.sur;

import java.util.Collection;
import java.util.HashMap;
import java.util.Vector;

import ar.edu.unicen.pladema.ui.model.g3d.Matrix;
import ar.edu.unicen.pladema.ui.model.g3d.Triangle;
import ar.edu.unicen.pladema.ui.model.g3d.Vertex;

public class Data3D {
	private Vector<Triangle> triangles = null;
	private HashMap<String, Vertex> vertexes = null;
	private double xMin = Double.MAX_VALUE;
	private double xMax = Double.MIN_VALUE;
	private double yMin = Double.MAX_VALUE;
	private double yMax = Double.MIN_VALUE;
	private double zMin = Double.MAX_VALUE;
	private double zMax = Double.MIN_VALUE;
	private boolean compiled;
	private Vertex light;
	
	public Data3D() {
		triangles = new Vector<Triangle>();
		vertexes = new HashMap<String, Vertex>();
		compiled=false;
		light = new Vertex();
		light.setX("0");
		light.setY("0");
		light.setZ("0");
	}
	public void compile() {
		for (Triangle triangle: triangles) {
			triangle.setVertexes(vertexes);
			triangle.getNormal();
		}
		xMin = light.getDX();
		xMax = light.getDX();
		yMin = light.getDY();
		yMax = light.getDY();
		zMin = light.getDZ();
		zMax = light.getDZ();
		for (Vertex vertex: vertexes.values()) {
			xMin = Math.min(vertex.getDX(), xMin);
			xMax = Math.max(vertex.getDX(), xMax);
			yMin = Math.min(vertex.getDY(), yMin);
			yMax = Math.max(vertex.getDY(), yMax);
			zMin = Math.min(vertex.getDZ(), zMin);
			zMax = Math.max(vertex.getDZ(), zMax);
		}
	}
	public void addTriangle(Triangle triangle) {
		compiled=false;
		this.triangles.add(triangle);
	}

	public void newVertex(String token) {
		compiled=false;
		vertexes.put(token, new Vertex());
	}
	public void newVertex(String vertexName, Vertex vertex) {
		compiled=false;
		vertexes.put(vertexName, vertex);
	}
	public void setVertexX(String vertexID, String token) {
		compiled=false;
		Vertex v = vertexes.get(vertexID);
		v.setX(token);
	}
	public void setVertexY(String vertexID, String token) {
		compiled=false;
		Vertex v = vertexes.get(vertexID);
		v.setY(token);
	}
	public void setVertexZ(String vertexID, String token) {
		compiled=false;
		vertexes.get(vertexID).setZ(token);
	}
	public Vertex getVertex(String vertexID) {
		return vertexes.get(vertexID);
	}
	
	public void printTriangles() {
		for (Triangle triangle : getTriangles()) {
			System.out.println("Triangulo: " + triangle.toString());
			Vertex vertex1 = triangle.getVertex1();
			System.out.println("\t" +  vertex1.toString());
			Vertex vertex2 = triangle.getVertex2();
			System.out.println("\t" +  vertex2.toString());
			Vertex vertex3 = triangle.getVertex3();
			System.out.println("\t" +  vertex3.toString());
			Vertex normal = triangle.getNormal();
			System.out.println("\t" + normal.toString());
		}
	}
	
	public void printVertexes() {
		for (String key : vertexes.keySet()) {
			System.out.println(key + ": " + vertexes.get(key).toString());
		}
	}
	public double minX() {
		return xMin;
	}
	public double maxX() {
		return xMax;
	}
	public double minY() {
		return yMin;
	}
	public double maxY() {
		return yMax;
	}
	public double minZ() {
		return zMin;
	}
	public double maxZ() {
		return zMax;
	}
	public Collection<Vertex> getVertexes() {
		return vertexes.values();
	}
	public Vector<Triangle> getTriangles() {
		if (!compiled) {compile();}
		return triangles;
	}
	public void sortTriangles() {
		ordenarQuicksort(triangles, 0, triangles.size()-1);
	}
	private static void ordenarQuicksort(Vector<Triangle> triangles, int primero, int ultimo){
    	int i=primero, j=ultimo;
    	Triangle pivote=triangles.get((primero + ultimo) / 2);
    	Triangle auxiliar;
 
    	do{
    		while(triangles.get(i).getAVGZ() < pivote.getAVGZ()) i++;    		
    		while(triangles.get(j).getAVGZ()>pivote.getAVGZ()) j--;
 
    		if (i<=j){
    			auxiliar=triangles.get(j);
    			triangles.set(j, triangles.get(i));
    			triangles.set(i, auxiliar);
    			i++;
    			j--;
    		}
 
    	} while (i<=j);
 
    	if(primero<j) ordenarQuicksort(triangles,primero, j);
    	if(ultimo>i) ordenarQuicksort(triangles,i, ultimo);
    }
	public Data3D transform(Matrix matrix)  {
		Data3D result = new Data3D();
		for(String vertexName : vertexes.keySet()) {
			Vertex vertex = vertexes.get(vertexName);
			Vertex vertexTransformed = matrix.multiply(vertex);
			result.newVertex(vertexName, vertexTransformed);
		}
		for(Triangle triangle : triangles) {
			try {
				result.addTriangle((Triangle)triangle.clone());
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
		}
		result.setLight(light);
		result.compile();
		return result;
	}
	public void setLight(Vertex light) {
		this.light = light;
	}
}
